package com.crt.nexus.oauth.authorization;

import com.crt.nexus.core.util.IdUtils;
import com.crt.nexus.security.authentication.ClientDetail;
import com.crt.nexus.security.authentication.UserDetail;
import com.crt.nexus.security.domain.bean.TokenBean;
import com.crt.nexus.security.jwt.JwtClaimsNames;
import com.crt.nexus.security.jwt.NimbusJwtEncoder;
import com.crt.nexus.security.util.JwtUtils;
import com.google.common.collect.Maps;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.stereotype.Component;

import java.util.Map;

import static com.crt.nexus.core.constant.SecurityConstants.BEARER;

@Slf4j
@Component
@RequiredArgsConstructor
public class AuthenticationBuilder {

    private final NimbusJwtEncoder encoder;

    public TokenBean buildPassword(Authentication authentication) {
        OauthAuthenticationToken oauthToken = (OauthAuthenticationToken) authentication;
        UserDetail user = (UserDetail) oauthToken.getPrincipal();
        Map<String, Object> parameters = oauthToken.getAdditionalParameters();
        ClientDetail client = (ClientDetail) oauthToken.getDetails();
        Jwt access = encoder.encode(
                JwtUtils.headers().build(),
                JwtUtils.accessTokenClaims(IdUtils.getUuid(), user.getUsername(), client.getClientId(),
                        client.getAccessTokenValiditySeconds(), parameters).build());
        Jwt refresh = encoder.encode(
                JwtUtils.headers().build(),
                JwtUtils.refreshTokenClaims(IdUtils.getUuid(), access.getId(), user.getUsername(),
                        client.getClientId(), client.getRefreshTokenValiditySeconds(), Maps.newHashMap()).build());
        return TokenBean.builder()
                .token(access.getTokenValue())
                .type(BEARER)
                .refresh(refresh.getTokenValue())
                .expires(client.getAccessTokenValiditySeconds() - 1)
                .jti(access.getId())
                .build();
    }

    public TokenBean buildRefresh(Authentication authentication) {
        OauthAuthenticationToken oauthToken = (OauthAuthenticationToken) authentication;
        Jwt jwt = (Jwt) oauthToken.getPrincipal();
        ClientDetail client = (ClientDetail) oauthToken.getDetails();
        Map<String, Object> parameters = oauthToken.getAdditionalParameters();
        Jwt access = encoder.encode(
                JwtUtils.headers().build(),
                JwtUtils.accessTokenClaims(IdUtils.getUuid(), jwt.getClaimAsString(JwtClaimsNames.SUB), client.getClientId(),
                        client.getAccessTokenValiditySeconds(), parameters).build());
        Jwt refresh = encoder.encode(
                JwtUtils.headers().build(),
                JwtUtils.refreshTokenClaims(jwt.getClaimAsString(JwtClaimsNames.JTI), access.getId(), access.getSubject(), client.getClientId(),
                        client.getRefreshTokenValiditySeconds(), Maps.newHashMap()).build());
        return TokenBean.builder()
                .token(access.getTokenValue())
                .type(BEARER)
                .refresh(refresh.getTokenValue())
                .expires(client.getAccessTokenValiditySeconds() - 1)
                .jti(access.getId())
                .build();
    }

}
